home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / infoplus.zip / INFOPLUS.ASM < prev    next >
Assembly Source File  |  1990-06-25  |  16KB  |  565 lines

  1. page    75, 110
  2.  
  3. ;--------------------------------------------------------------------
  4. ;
  5. ;       INFOPLUS.ASM
  6. ;
  7. ;       Version 1.0
  8. ;
  9. ;       Two subprograms used by INFOPLUS.PAS:
  10. ;
  11. ;               CPUID           - identifies host CPU and NDP (if
  12. ;                                       any)
  13. ;               DISKREAD        - reads absolute sectors from disk
  14. ;
  15. ;       Originally by:
  16. ;       Steve Grant
  17. ;       Long Beach, CA
  18. ;       January 13, 1989
  19. ;
  20. ;       mods by Andrew Rossmann (6/24/90)
  21. ;       286/386/486 detection adapted from code by Robert Collins.
  22. ;--------------------------------------------------------------------
  23.  
  24. .286P
  25. .8087
  26.  
  27.         public  CPUID, DISKREAD
  28.  
  29. ;-----------------------------------------------------------------------------
  30. ; 80486 instruction macro -- because MASM 5.1 doesn't support the 80486!
  31. ;-----------------------------------------------------------------------------
  32. XADD    macro
  33.         db      0fh,0C0h,0D2h           ; 80486 instruction macro
  34. ENDM
  35.  
  36. CODE    segment byte
  37.  
  38. ;       Conditional jumps are all coded with the SHORT qualifier in
  39. ;       order to minimize the size of the .OBJ file output of Turbo
  40. ;       Assembler.
  41.  
  42. ;--------------------------------------------------------------------
  43.  
  44. CPUID   proc    near
  45.  
  46. assume  cs:CODE, ds:DATA, es:nothing, ss:nothing
  47.  
  48. ;       On entry:
  49. ;
  50. ;               BP
  51. ;       SP =>   near return address
  52. ;               offset  of a cpu_info_t record
  53. ;               segment "  "     "        "
  54. ;
  55. ;       On exit, the cpu_info_t record has been filled in as follows:
  56. ;
  57. ;               byte    = CPU type
  58. ;               word    = Machine Status Word
  59. ;               6 bytes = Global Descriptor Table
  60. ;               6 bytes = Interrupt Descriptor Table
  61. ;               boolean = segment register change/interrupt flag
  62. ;               byte    = NDP type
  63. ;               word    = NDP control word
  64.  
  65. mCPU    equ     byte ptr [bx]
  66. mMSW    equ     word ptr [bx + 1]
  67. mGDT    equ     [bx + 3]
  68. mIDT    equ     [bx + 9]
  69. mchkint equ     byte ptr [bx + 15]
  70. mNDP    equ     byte ptr [bx + 16]
  71. mNDPCW  equ     word ptr [bx + 17]
  72.  
  73. f8088   equ     0
  74. f8086   equ     1
  75. fV20    equ     2
  76. fV30    equ     3
  77. f80188  equ     4
  78. f80186  equ     5
  79. f80286  equ     6
  80. f80386  equ     7
  81. f80486  equ     8
  82. funk    =       0FFH
  83.  
  84. false   equ     0
  85. true    equ     1
  86.  
  87.         push    bp
  88.         mov     bp,sp
  89.         push    ds
  90.         lds     bx,[bp + 4]
  91.         call    cpu
  92.         call    chkint
  93.         call    ndp
  94.         pop     ds
  95.         pop     bp
  96.         ret     4
  97.  
  98. ;--------------------------------------------------------------------
  99.  
  100. cpu:
  101.  
  102. ; interrupt of multi-prefix string instruction
  103.  
  104.         mov     mCPU,funk               ;set CPU type to unknown
  105.         sti
  106.         mov     cx,0FFFFH
  107. rep     lods    byte ptr es:[si]
  108.         jcxz    short cpu_02
  109.         call    piq
  110.         cmp     dx,4
  111.         jg      short cpu_01
  112.         mov     mCPU,f8088
  113.         ret
  114. cpu_01:
  115.         cmp     dx,6
  116.         jne     short cpu_01a
  117.         mov     mCPU,f8086
  118. cpu_01a:
  119.         ret
  120. cpu_02:
  121.  
  122. ; number of bits in displacement register used by shift
  123.  
  124.         mov     al,0FFH
  125.         mov     cl,20H
  126.         shl     al,cl
  127.         or      al,al
  128.         jnz     short cpu_04
  129.         call    piq
  130.         cmp     dx,4
  131.         jg      short cpu_03
  132.         mov     mCPU,fV20
  133.         ret
  134. cpu_03:
  135.         cmp     dx,6
  136.         jne     short CPUID_done
  137.         mov     mCPU,fV30
  138.         ret
  139. cpu_04:
  140.  
  141. ; order of write/decrement by PUSH SP
  142.  
  143.         push    sp
  144.         pop     ax
  145.         cmp     ax,sp
  146.         je      short cpu_06
  147.         call    piq
  148.         cmp     dx,4
  149.         jg      short cpu_05
  150.         mov     mCPU,f80188
  151.         ret
  152. cpu_05:
  153.         cmp     dx,6
  154.         jne     short CPUID_done
  155.         mov     mCPU,f80186
  156.         ret
  157.  
  158.  
  159. ; The following code is adapted from a program by Robert Collins
  160. ;since we probably have a 286, 386 or 486, we'll trap the invalid opcode
  161. ;handler, and try to determine the cpu type by using various opcodes.
  162. ;First, though, grab some tables
  163.  
  164. cpu_06:
  165.         smsw    mMSW
  166.         sgdt    mGDT
  167.         sidt    mIDT
  168. ;-----------------------------------------------------------------------------
  169. ; Setup INT6 handler
  170. ;-----------------------------------------------------------------------------
  171.         push    bx                      ;save bx
  172.         mov     ax,3506h                ;get INT 6 pointer
  173.         int     21h
  174.         mov     old_int06_seg,es        ;save
  175.         mov     old_int06_ofs,bx
  176.         push    ds                      ;save DS
  177.         mov     dx,seg INT6_handler     ;point to new handler
  178.         mov     ds,dx
  179.         mov     dx,offset INT6_handler
  180.         mov     ax,2506h                ;put into effect
  181.         int     21h
  182.         pop     ds                      ;restore DS
  183.         pop     bx
  184.         mov     mCPU,f80486             ; initialize CPU flag
  185.         xor     cx,cx                   ; initialize semaphore
  186.  
  187. ;-----------------------------------------------------------------------------
  188. ; Now, try and determine which CPU we are by executing invalid opcodes.
  189. ; The instructions I chose to invoke invalid opcodes, are themselves rather
  190. ; benign.  In each case, the chosen instruction modifies the DX register,
  191. ; and nothing else.  No system parameters are changed, e.g. protected mode,
  192. ; or other CPU dependant features.
  193. ;-----------------------------------------------------------------------------
  194. ; The 80486 instruction 'XADD' xchanges the registers, then adds them.
  195. ; The exact syntax for a '486 compiler would be:  XADD  DX,DX.
  196. ;-----------------------------------------------------------------------------
  197.         XADD    ;DX,DX                  ; 80486
  198.         jcxz    CPU_exit
  199.         mov     mCPU,f80386             ; set 80386 semaphore
  200.         xor     cx,cx                   ; CX=0
  201.  
  202. ;-----------------------------------------------------------------------------
  203. ; For a description on the effects of the following instructions, look in
  204. ; the Intel Programmers Reference Manual's for the 80186, 80286, or 80386.
  205. ;-----------------------------------------------------------------------------
  206. .386
  207.         mov     edx,edx                 ; 80386
  208. .286P
  209.         jcxz    CPU_exit
  210.         mov     mCPU,f80286             ; set 80286 semaphore
  211.         xor     cx,cx                   ; CX=0
  212.  
  213.         smsw    dx                      ; 80286
  214.         jcxz    CPU_exit
  215.         mov     mCPU,funk               ; set unknown CPU
  216.  
  217. CPU_exit:
  218.         push    ds                      ;save DS
  219.         lds     dx,old_int06            ;get old pointer
  220.         mov     ax,2506h                ;restore it
  221.         int     21h
  222.         pop     ds
  223.  
  224. ;!!!!!!!
  225. ;!!! Original 286/386 detection code. Commented out but left in in
  226. ;!!! case of problems.
  227. ;!!!!!!!
  228. ; try to alter flag register bits 15-12
  229. ;
  230. ;       pushf
  231. ;       pop     ax
  232. ;       mov     cx,ax
  233. ;       xor     cx,0F000H
  234. ;       push    cx
  235. ;       popf
  236. ;       pushf
  237. ;       pop     cx
  238. ;       cmp     ax,cx
  239. ;       jne     short cpu_07
  240. ;       mov     mCPU,f80286
  241. ;       ret
  242. ;cpu_07:
  243. ;       mov     mCPU,f80386
  244. ;       ret
  245. ;cpu_08:
  246. ;       mov     mCPU,funk
  247. CPUID_done:
  248.         ret
  249.  
  250. ;--------------------------------------------------------------------
  251.  
  252. piq:
  253.  
  254. ;       On exit:
  255. ;
  256. ;               DX      = length of prefetch instruction queue
  257. ;
  258. ;       This subroutine uses self-modifying code, but can
  259. ;       nevertheless be run repeatedly in the course of the calling
  260. ;       program.
  261.  
  262. count   =       7
  263. opincdx equ     42H                     ; inc dx opcode
  264. opnop   equ     90H                     ; nop opcode
  265.  
  266.         mov     al,opincdx
  267.         mov     cx,count
  268.         push    cx
  269.         push    cs
  270.         pop     es
  271.         mov     di,offset piq_01 - 1
  272.         push    di
  273.         std
  274.         rep stosb
  275.         mov     al,opnop
  276.         pop     di
  277.         pop     cx
  278.         xor     dx,dx
  279.         cli
  280.         rep stosb
  281.         rept    count
  282.         inc     dx
  283.         endm
  284. piq_01:
  285.         sti
  286.         ret
  287.  
  288. ;--------------------------------------------------------------------
  289.  
  290. chkint:
  291.  
  292. ; save old INT 01H vector
  293.  
  294.         push    bx
  295.         mov     ax,3501H
  296.         int     21H
  297.         mov     old_int01_ofs,bx
  298.         mov     old_int01_seg,es
  299.         pop     bx
  300.  
  301. ; redirect INT 01H vector
  302.  
  303.         push    ds
  304.         mov     ax,2501H
  305.         mov     dx,seg new_int01
  306.         mov     ds,dx
  307.         mov     dx,offset new_int01
  308.         int     21H
  309.         pop     ds
  310.  
  311. ; set TF and change SS -- did we trap on following instruction?
  312.  
  313.         pushf
  314.         pop     ax
  315.         or      ah,01H                  ; set TF
  316.         push    ax
  317.         popf
  318.         push    ss                      ; CPU may wait one
  319.                                         ; instruction before
  320.                                         ; recognizing single step
  321.                                         ; interrupt
  322.         pop     ss
  323. chkint_01:                              ; shouldn't ever trap here
  324.  
  325. ; restore old INT 01H vector
  326.  
  327.         push    ds
  328.         mov     ax,2501H
  329.         lds     dx,old_int01
  330.         int     21H
  331.         pop     ds
  332.         ret
  333.  
  334. ;--------------------------------------------------------------------
  335.  
  336. new_int01:
  337.  
  338. ;       INT 01H handler (single step)
  339. ;
  340. ;       On entry:
  341. ;
  342. ;       SP =>   IP
  343. ;               CS
  344. ;               flags
  345.  
  346.         sti
  347.         pop     ax                      ; IP
  348.         cmp     ax,offset chkint_01
  349.         jb      short new_int01_03
  350.         je      short new_int01_01
  351.         mov     mchkint,false
  352.         jmp     short new_int01_02
  353. new_int01_01:
  354.         mov     mchkint,true
  355. new_int01_02:
  356.         pop     cx                      ; CS
  357.         pop     dx                      ; flags
  358.         and     dh,0FEH                 ; turn off TF
  359.         push    dx                      ; flags
  360.         push    cx                      ; CS
  361. new_int01_03:
  362.         push    ax                      ; IP
  363.         iret
  364.  
  365. ;-----------------------------------------------------------------------------
  366. ; INT6 handler sets a semaphore (CX=FFFF) and adjusts the return address to
  367. ; point past the invalid opcode.
  368. ;-----------------------------------------------------------------------------
  369. INT6_handler:
  370.         enter   0,0                     ; create new stack frame
  371.         dec     cx                      ; make CX=FFFF
  372.         add     word ptr ss:[bp][2],3   ; point past invalid opcode
  373.         leave
  374.         iret
  375.  
  376. ;--------------------------------------------------------------------
  377.  
  378. ndp:
  379.  
  380. fnone   equ     0
  381. f8087   equ     1
  382. f80287  equ     2
  383. f80387  equ     3
  384. funk    =       0FFH
  385.  
  386.         mov     word ptr ndp_cw,0000H
  387.         cli
  388.  
  389. ; The next three 80x87 instructions cannot carry the WAIT prefix,
  390. ; because there may not be an 80x87 for which to wait.  The WAIT is
  391. ; therefore emulated with a MOV CX,<value>! LOOP $ combination.
  392.  
  393.                                         ;       CPU     NDP
  394.         fnsave  ndp_save                ;        14     221
  395.         mov     cx,(221-6-1)/17+1       ;         4
  396.         loop    $                       ;  17*CX-12
  397.                                         ;   17*CX+6
  398.  
  399.         fninit                          ;         8       8
  400.         mov     cx,(8-0-1)/17+1         ;         4
  401.         loop    $                       ;  17*CX-12
  402.                                         ;     17*CX
  403.  
  404.         fnstcw  ndp_cw                  ;        14      24
  405.         mov     cx,(24-2-1)/17+1        ;         4
  406.         loop    $                       ;  17*CX-12
  407.                                         ;   17*CX+2
  408.  
  409.         sti
  410.         mov     ax,ndp_cw
  411.         cmp     ax,0000H
  412.         jne     short ndp_01
  413.         mov     mNDP,fnone
  414.         ret
  415. ndp_01:
  416.         cmp     ax,03FFH
  417.         jne     short ndp_02
  418.         mov     mNDP,f8087
  419.         jmp     short ndp_04
  420. ndp_02:
  421.  
  422. .287
  423.  
  424.         cmp     ax,037FH
  425.         jne     short ndp_05
  426.         fld1
  427.         fldz
  428.         fdiv
  429.         fld1
  430.         fchs
  431.         fldz
  432.         fdiv
  433.         fcom
  434.         fstsw   ndp_sw
  435.         mov     ax,ndp_sw
  436.         and     ah,41H                  ; C3, C0
  437.         cmp     ah,40H                  ; ST(0) = ST(1)
  438.         jne     short ndp_03
  439.         mov     mNDP,f80287
  440.         jmp     short ndp_04
  441. ndp_03:
  442.         cmp     ah,01H                  ; ST(0) < ST(1)
  443.         jne     short ndp_05
  444.         mov     mNDP,f80387
  445. ndp_04:
  446.  
  447. .8087
  448.  
  449.         frstor  ndp_save
  450.         fstcw   mNDPCW
  451.         ret
  452. ndp_05:
  453.         mov     mNDP,funk
  454.         ret
  455.  
  456. CPUID   endp
  457.  
  458. ;--------------------------------------------------------------------
  459.  
  460. DISKREAD        proc    near
  461.  
  462. assume cs:CODE, ds:DATA, es:nothing
  463.  
  464. ;       On entry:
  465. ;
  466. ;               BP
  467. ;       SP =>   near return address
  468. ;               offset  of disk buffer
  469. ;               segment "   "     "
  470. ;               number of sectors to read
  471. ;               starting logical sector number
  472. ;               drive number (0=A, 1=B, etc.)
  473. ;
  474. ;       On exit:
  475. ;
  476. ;               AX      = function result
  477. ;                       00      - function successful
  478. ;                       01..FF  - DOS INT 25H error result
  479.  
  480.         drive                   equ     [bp + 12]
  481.         starting_sector         equ     [bp + 10]
  482.         number_of_sectors       equ     [bp + 8]
  483.         buffer                  equ     [bp + 4]
  484.  
  485.         push    bp
  486.         mov     bp,sp
  487.         mov     ax,3000h                ;get DOS version
  488.         int     21h
  489.         cmp     al,4                    ;DOS 4?
  490.         jb      read3                   ;Read assuming DOS 3.x
  491.         mov     al,drive
  492.         mov     bx,starting_sector      ;copy info into parameter block
  493.         mov     extd_starting_sector_lo,bx
  494.         mov     extd_starting_sector_hi,0       ;We're only using lower part
  495.         mov     bx,number_of_sectors
  496.         mov     extd_number_of_sectors,bx
  497.         les     bx,buffer               ;get seg:ofs of buffer in ES:BX
  498.         mov     extd_bufofs,bx          ;put into block
  499.         mov     extd_bufseg,es
  500.         mov     bx,offset dos4_block    ;DS:BX points to block
  501.         mov     cx,-1                   ;-1 means extended read
  502.         push    ds                      ;save DS (not really needed, but lets
  503.                                         ;me share code with DOS 3 read.)
  504.         jmp     short readit
  505.  
  506. read3:  mov     al,drive
  507.         mov     dx,starting_sector
  508.         mov     cx,number_of_sectors
  509.         push    ds
  510.         lds     bx,buffer               ;get seg:ofs of buffer in DS:BX
  511. readit: int     25H
  512.         inc     sp                      ; fix broken stack
  513.         inc     sp
  514.         pop     ds
  515.         jc      short diskread_01
  516.         xor     ax,ax
  517.  
  518. diskread_01:
  519.  
  520.         pop     bp
  521.         ret     10
  522.  
  523. DISKREAD        endp
  524.  
  525. CODE    ends
  526.  
  527. ;--------------------------------------------------------------------
  528.  
  529. DATA    segment byte
  530.  
  531. ; storage for CPUID
  532.  
  533. ; redirected INT 01H vector
  534.  
  535. old_int01       label   dword
  536. old_int01_ofs   dw      ?
  537. old_int01_seg   dw      ?
  538.  
  539. ; redirected INT 6 vector
  540. old_int06       label   dword
  541. old_int06_ofs   dw      ?
  542. old_int06_seg   dw      ?
  543.  
  544. ; storage for NDPID
  545.  
  546. ; 80x87 control word after initialization, status word after divide by zero
  547.  
  548. ndp_cw          dw      ?
  549. ndp_save        db      94 dup (?)
  550. ndp_sw          dw      ?
  551.  
  552. ; storage for DISKREAD
  553.  
  554. ; DOS 4.0 extended read parameter block
  555. dos4_block                      label   byte
  556. extd_starting_sector_lo         dw      ?
  557. extd_starting_sector_hi         dw      ?
  558. extd_number_of_sectors          dw      ?
  559. extd_bufofs                     dw      ?
  560. extd_bufseg                     dw      ?
  561.  
  562. DATA    ends
  563.  
  564.         end
  565.